using System;
using System.Collections.Generic;
using FireStarter.Base;
using FireStarter.CodeGeneration;
using FireStarterModeller.BO;
using FireStarterModeller.Test.BO;
using FireStarterModeller.UI.CodeGeneration;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using Habanero.BO.Loaders;
using Habanero.Faces.Base;
using Habanero.Faces.Win;
using NUnit.Framework;

namespace FireStarterModeller.Test.UI.CodeGeneration
{
    [TestFixture]
    public class TestCodeGenerationController
    {
        [TestFixtureSetUp]
        public void SetUpFixture()
        {
            ClassDef.ClassDefs.Clear();
            ClassDef.ClassDefs.Add(new XmlClassDefsLoader(BOBroker.GetClassDefsXml(), new DtdLoader()).LoadClassDefs());
        }

        [SetUp]
        public void Setup()
        {
            BORegistry.DataAccessor = new DataAccessorInMemory();
        }

        [Test]
        public void Test_Construct()
        {
            //---------------Set up test pack-------------------
            GenerationSettings generationSettings = new GenerationSettings();
            //---------------Assert Precondition----------------
            Assert.IsNotNull(generationSettings);
            //---------------Execute Test ----------------------
            CodeGenerationController controller = new CodeGenerationController(generationSettings);
            //---------------Test Result -----------------------
            Assert.AreSame(generationSettings, controller.GenerationSettings);
        }

        [Test]
        public void Test_Construct_WithNullGenerationSettings_ShouldRaiseError()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new CodeGenerationController(null);
                Assert.Fail("expected ArgumentNullException");
            }
            //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("generationSettings", ex.ParamName);
            }
        }

        [Test]
        public void Test_LoadSolutionTypes_WhenNoSolutionTypesLoaded_ShouldLoadDefaultSolutionTypes()
        {
            CodeGenerationController controller = CreateCodeGenerationController();
            //---------------Assert Precondition----------------
            BusinessObjectCollection<SolutionType> allSolutionTypes = Broker.GetBusinessObjectCollection<SolutionType>("", "Name");
            Assert.AreEqual(0, allSolutionTypes.Count);
            //---------------Execute Test ----------------------
            BusinessObjectCollection<SolutionType> returnedSolutionTypes = controller.LoadSolutionTypes();
            //---------------Test Result -----------------------
            Assert.AreEqual(3, returnedSolutionTypes.Count);
            allSolutionTypes.Refresh();
            Assert.AreEqual(3, allSolutionTypes.Count);
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_WIN, returnedSolutionTypes[2].Name);
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_VWG, returnedSolutionTypes[1].Name);
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_DUALWINVWG, returnedSolutionTypes[0].Name);
        }

        [Test]
        public void Test_LoadSolutionTypes_WhenSolutionTypesAlreadyLoaded_ShouldNotLoadMoreSolutionTypes()
        {
            CodeGenerationController controller = CreateCodeGenerationController();
            BusinessObjectCollection<SolutionType> loadedSolutionTypes = controller.GenerateDefaultSolutionTypes();
            //---------------Assert Precondition----------------
            BusinessObjectCollection<SolutionType> allSolutionTypes = Broker.GetBusinessObjectCollection<SolutionType>("", "Name");
            Assert.AreEqual(loadedSolutionTypes.Count, allSolutionTypes.Count);
            //---------------Execute Test ----------------------
            BusinessObjectCollection<SolutionType> returnedSolutionTypes = controller.LoadSolutionTypes();
            //---------------Test Result -----------------------
            Assert.AreEqual(loadedSolutionTypes.Count, returnedSolutionTypes.Count);
            allSolutionTypes.Refresh();
            Assert.AreEqual(loadedSolutionTypes.Count, allSolutionTypes.Count);
        }

        [Test]
        public void Test_GenerateDefaultSolutionTypes_CreatesSolutionTypes()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController controller = CreateCodeGenerationController();
            //---------------Assert Precondition----------------
            BusinessObjectCollection<SolutionType> allSolutionTypes = Broker.GetBusinessObjectCollection<SolutionType>("", "Name");
            Assert.AreEqual(0, allSolutionTypes.Count);
            //---------------Execute Test ----------------------
            BusinessObjectCollection<SolutionType> returnedSolutionTypes = controller.GenerateDefaultSolutionTypes();
            //---------------Test Result -----------------------
            Assert.AreEqual(3, returnedSolutionTypes.Count);
            allSolutionTypes.Refresh();
            Assert.AreEqual(3, allSolutionTypes.Count);
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_WIN, returnedSolutionTypes[2].Name);
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_VWG, returnedSolutionTypes[1].Name);
            Assert.AreEqual(GenerationTypes.SOLUTION_TYPE_DUALWINVWG, returnedSolutionTypes[0].Name);
        }

        private static CodeGenerationController CreateCodeGenerationController()
        {
            GenerationSettings generationSettings = new GenerationSettings();
            return new CodeGenerationController(generationSettings);
        }

        [Test]
        public void Test_GenerateDefaultSolutionTypes_CreatesAllProjectTypes()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController controller = CreateCodeGenerationController();
            //---------------Assert Precondition----------------
            BusinessObjectCollection<ProjectType> projectTypes = Broker.GetBusinessObjectCollection<ProjectType>("", "Name");
            Assert.AreEqual(0, projectTypes.Count);
            //---------------Execute Test ----------------------
            controller.GenerateDefaultSolutionTypes();
            //---------------Test Result -----------------------
            projectTypes = Broker.GetBusinessObjectCollection<ProjectType>("", "Name");
            Assert.AreEqual(11, projectTypes.Count);
            string[] projectNames = {
                                        GenerationTypes.PROJECT_TYPE_BO,
                                        GenerationTypes.PROJECT_TYPE_LOGIC,
                                        GenerationTypes.PROJECT_TYPE_MAIN_VWG,
                                        GenerationTypes.PROJECT_TYPE_MAIN_WIN,
                                        GenerationTypes.PROJECT_TYPE_TEST_BASE,
                                        GenerationTypes.PROJECT_TYPE_TEST_BO,
                                        GenerationTypes.PROJECT_TYPE_TEST_LOGIC,
                                        GenerationTypes.PROJECT_TYPE_TEST_UI,
                                        //GenerationTypes.PROJECT_TYPE_UI,
                                        GenerationTypes.PROJECT_TYPE_UI_BASE,
                                        GenerationTypes.PROJECT_TYPE_UI_VWG,
                                        GenerationTypes.PROJECT_TYPE_UI_WIN
                                    };
            for (int num = 0; num < projectNames.Length; num++)
            {
                Assert.AreEqual(projectNames[num], projectTypes[num].Name);
            }
        }

        [Test]
        public void Test_GenerateDefaultSolutionTypes_WinFormsGetsCorrectProjectTypes()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController controller = CreateCodeGenerationController();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            controller.GenerateDefaultSolutionTypes();
            //---------------Test Result -----------------------
            string criteria = String.Format("Name = '{0}'", GenerationTypes.SOLUTION_TYPE_WIN);
            SolutionType solutionType = Broker.GetBusinessObject<SolutionType>(criteria);
            List<ProjectType> linkedProjects = SolutionType.GetLinkedProjects(solutionType);
            List<string> linkedProjectNames = linkedProjects.ConvertAll(input => input.Name);
            string[] expectedProjectTypes = {
                                                GenerationTypes.PROJECT_TYPE_BO,
                                                GenerationTypes.PROJECT_TYPE_LOGIC,
                                                GenerationTypes.PROJECT_TYPE_MAIN_WIN,
                                                GenerationTypes.PROJECT_TYPE_TEST_BASE,
                                                GenerationTypes.PROJECT_TYPE_TEST_BO,
                                                GenerationTypes.PROJECT_TYPE_TEST_LOGIC,
                                                GenerationTypes.PROJECT_TYPE_TEST_UI,
                                                GenerationTypes.PROJECT_TYPE_UI_WIN
                                            };
            Assert.AreEqual(expectedProjectTypes.Length, linkedProjects.Count, "Should not be any extra project types");
            foreach (string expectedProjectType in expectedProjectTypes)
            {
                Assert.Contains(expectedProjectType, linkedProjectNames);
            }
        }

        [Test]
        public void Test_GenerateDefaultSolutionTypes_WebGuiGetsCorrectProjectTypes()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController controller = CreateCodeGenerationController();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            controller.GenerateDefaultSolutionTypes();
            //---------------Test Result -----------------------
            string criteria = String.Format("Name = '{0}'", GenerationTypes.SOLUTION_TYPE_VWG);
            SolutionType solutionType = Broker.GetBusinessObject<SolutionType>(criteria);
            List<ProjectType> linkedProjects = SolutionType.GetLinkedProjects(solutionType);
            List<string> linkedProjectNames = linkedProjects.ConvertAll(input => input.Name);

            string[] expectedProjectTypes = {
                                                GenerationTypes.PROJECT_TYPE_BO,
                                                GenerationTypes.PROJECT_TYPE_LOGIC,
                                                GenerationTypes.PROJECT_TYPE_MAIN_VWG,
                                                GenerationTypes.PROJECT_TYPE_TEST_BASE,
                                                GenerationTypes.PROJECT_TYPE_TEST_BO,
                                                GenerationTypes.PROJECT_TYPE_TEST_LOGIC,
                                                GenerationTypes.PROJECT_TYPE_TEST_UI,
                                                GenerationTypes.PROJECT_TYPE_UI_VWG
                                            };
            Assert.AreEqual(expectedProjectTypes.Length, linkedProjects.Count, "Should not be any extra project types");
            foreach (string expectedProjectType in expectedProjectTypes)
            {
                Assert.Contains(expectedProjectType, linkedProjectNames);
            }
        }

        [Test]
        public void Test_GenerateDefaultSolutionTypes_DualWinFormWebGuiGetsCorrectProjectTypes()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController controller = CreateCodeGenerationController();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            controller.GenerateDefaultSolutionTypes();
            //---------------Test Result -----------------------
            string criteria = String.Format("Name = '{0}'", GenerationTypes.SOLUTION_TYPE_DUALWINVWG);
            SolutionType solutionType = Broker.GetBusinessObject<SolutionType>(criteria);
            List<ProjectType> linkedProjects = SolutionType.GetLinkedProjects(solutionType);
            List<string> linkedProjectNames = linkedProjects.ConvertAll(input => input.Name);

            string[] expectedProjectTypes = {
                                                GenerationTypes.PROJECT_TYPE_BO,
                                                GenerationTypes.PROJECT_TYPE_LOGIC,
                                                GenerationTypes.PROJECT_TYPE_MAIN_VWG,
                                                GenerationTypes.PROJECT_TYPE_MAIN_WIN,
                                                GenerationTypes.PROJECT_TYPE_TEST_BASE,
                                                GenerationTypes.PROJECT_TYPE_TEST_BO,
                                                GenerationTypes.PROJECT_TYPE_TEST_LOGIC,
                                                GenerationTypes.PROJECT_TYPE_TEST_UI,
                                                GenerationTypes.PROJECT_TYPE_UI_BASE,
                                                GenerationTypes.PROJECT_TYPE_UI_VWG,
                                                GenerationTypes.PROJECT_TYPE_UI_WIN
                                            };
            Assert.AreEqual(expectedProjectTypes.Length, linkedProjects.Count, "Should not be any extra project types");
            foreach (string expectedProjectType in expectedProjectTypes)
            {
                Assert.Contains(expectedProjectType, linkedProjectNames);
            }
        }

        [Test]
        public void Test_ChangingSolutionType_PopulatesProjectTypes()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController codeGenerationController = CreateCodeGenerationController();
            GenerationSettings generationSettings = codeGenerationController.GenerationSettings;
            SolutionType solutionType = GetRandomSolutionType(codeGenerationController);
            int solutionProjectTypesCount = solutionType.SolutionTypeProjects.Count;
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(0, solutionProjectTypesCount);
            Assert.IsNull(generationSettings.SolutionType);
            Assert.AreEqual(0, generationSettings.ProjectTypeGenerations.Count);
            //---------------Execute Test ----------------------
            generationSettings.SolutionType = solutionType;
            //---------------Test Result -----------------------
            Assert.AreSame(solutionType, generationSettings.SolutionType);
            Assert.AreEqual(solutionProjectTypesCount, generationSettings.ProjectTypeGenerations.Count, solutionProjectTypesCount + " projects should have been added");
        }

        [Test]
        //TODO Mark 14 Oct 2009: This should be changed to rather look at a setting on the ProjectType class
        public void Test_ChangingSolutionType_TestProjectsNotTickedByDefault()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController codeGenerationController = CreateCodeGenerationController();
            GenerationSettings generationSettings = codeGenerationController.GenerationSettings;
            SolutionType solutionType = GetRandomSolutionType(codeGenerationController);
            //---------------Assert Precondition----------------
            Assert.IsNull(generationSettings.SolutionType);
            Assert.AreEqual(0, generationSettings.ProjectTypeGenerations.Count);
            //---------------Execute Test ----------------------
            generationSettings.SolutionType = solutionType;
            //---------------Test Result -----------------------
            Assert.AreSame(solutionType, generationSettings.SolutionType);
            BusinessObjectCollection<ProjectTypeGeneration> projectTypeGenerations = generationSettings.ProjectTypeGenerations;
            foreach (ProjectTypeGeneration projectTypeGeneration in projectTypeGenerations)
            {
                if (projectTypeGeneration.ProjectType.Name.ToUpper().Contains("TEST"))
                {
                    Assert.IsFalse(projectTypeGeneration.ToBeGenerated.Value);
                }
            }
        }

        private static SolutionType GetRandomSolutionType(CodeGenerationController codeGenerationController)
        {
            BusinessObjectCollection<SolutionType> solutionTypes = codeGenerationController.GenerateDefaultSolutionTypes();
            return solutionTypes[TestUtilsShared.GetRandomInt(0, 2)];
        }

        [Test]
        public void Test_ChangingSolutionType_PopulatesProjectNames()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController codeGenerationController = CreateCodeGenerationController();
            GenerationSettings generationSettings = codeGenerationController.GenerationSettings;
            generationSettings.Solution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            string originalSolutionName = generationSettings.Solution.SolutionName;
            string customSolutionName = TestUtilsShared.GetRandomString();
            generationSettings.SolutionName = customSolutionName;
            SolutionType solutionType = GetRandomSolutionType(codeGenerationController);
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(originalSolutionName, customSolutionName);
            Assert.IsNull(generationSettings.SolutionType);
            Assert.AreEqual(0, generationSettings.ProjectTypeGenerations.Count);
            //---------------Execute Test ----------------------
            generationSettings.SolutionType = solutionType;
            //---------------Test Result -----------------------
            Assert.AreSame(solutionType, generationSettings.SolutionType);
            ProjectTypeGeneration firstProjectTypeGen = generationSettings.ProjectTypeGenerations[0];
            StringAssert.Contains(customSolutionName, firstProjectTypeGen.ProjectName);
        }

        [Test]
        public void Test_ChangingSolutionType_WhenExistingProjectTypes_ShouldDeleteAndRepopulateProjectTypes()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController codeGenerationController = CreateCodeGenerationController();
            GenerationSettings generationSettings = codeGenerationController.GenerationSettings;
            generationSettings.Solution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            string originalSolutionName = generationSettings.Solution.SolutionName;
            string customSolutionName = TestUtilsShared.GetRandomString();
            generationSettings.SolutionName = customSolutionName;
            BusinessObjectCollection<SolutionType> solutionTypes = codeGenerationController.GenerateDefaultSolutionTypes();
            SolutionType oldSolutionType = solutionTypes[0];
            int oldSolutionProjectCount = oldSolutionType.SolutionTypeProjects.Count;
            SolutionType newSolutionType = solutionTypes[1];
            int newSolutionProjectCount = newSolutionType.SolutionTypeProjects.Count;
            generationSettings.SolutionType = oldSolutionType;
            generationSettings.Save();
            //---------------Assert Precondition----------------
            Assert.AreSame(oldSolutionType, generationSettings.SolutionType);
            Assert.AreNotEqual(oldSolutionProjectCount, newSolutionProjectCount);
            Assert.AreEqual(oldSolutionProjectCount, generationSettings.ProjectTypeGenerations.Count);
            //---------------Execute Test ----------------------
            generationSettings.SolutionType = newSolutionType;
            //---------------Test Result -----------------------
            Assert.AreSame(newSolutionType, generationSettings.SolutionType);
            Assert.AreEqual(newSolutionProjectCount, generationSettings.ProjectTypeGenerations.Count);
        }

        [Test]
        public void Test_Cancel_WhenExistingSolutionTypeChanged_ShouldRevertToOldProjectTypes()
        {
            //---------------Set up test pack-------------------
            CodeGenerationController codeGenerationController = CreateCodeGenerationController();
            GenerationSettings generationSettings = codeGenerationController.GenerationSettings;
            generationSettings.Solution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            string originalSolutionName = generationSettings.Solution.SolutionName;
            string customSolutionName = TestUtilsShared.GetRandomString();
            generationSettings.SolutionName = customSolutionName;
            BusinessObjectCollection<SolutionType> solutionTypes = codeGenerationController.GenerateDefaultSolutionTypes();
            SolutionType oldSolutionType = solutionTypes[0];
            int oldSolutionProjectCount = oldSolutionType.SolutionTypeProjects.Count;
            SolutionType newSolutionType = solutionTypes[1];
            int newSolutionProjectCount = newSolutionType.SolutionTypeProjects.Count;
            generationSettings.SolutionType = oldSolutionType;
            generationSettings.Save();
            generationSettings.SolutionType = newSolutionType;
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(oldSolutionProjectCount, newSolutionProjectCount);
            Assert.AreSame(newSolutionType, generationSettings.SolutionType);
            Assert.AreEqual(newSolutionProjectCount, generationSettings.ProjectTypeGenerations.Count);
            //---------------Execute Test ----------------------
            generationSettings.CancelEdits();
            //---------------Test Result -----------------------
            Assert.AreSame(oldSolutionType, generationSettings.SolutionType);
            Assert.AreEqual(oldSolutionProjectCount, generationSettings.ProjectTypeGenerations.Count);
        }
    }
}